package org.bdware.doip.examples;

import org.apache.log4j.Logger;
import org.bdware.doip.core.doipMessage.DoipMessage;
import org.bdware.doip.core.doipMessage.DoipMessageFactory;
import org.bdware.doip.core.exception.DoipConnectException;
import org.bdware.doip.core.model.digitalObject.DigitalObject;
import org.bdware.doip.core.model.metadata.SearchParameter;
import org.bdware.doip.core.model.operations.BasicOperations;
import org.bdware.doip.endpoint.doipClient.DoipClient;
import org.bdware.doip.endpoint.doipClient.DoipClientChannel;
import org.bdware.doip.endpoint.doipClient.DoipClientChannelGenerator;
import org.bdware.doip.endpoint.doipClient.DoipMessageCallback;

import java.net.URISyntaxException;

public class DoipClientImpl implements DoipClient {

    DoipClientChannel doipChannel;
    String recipientID;
    String serverURL = null;
    Logger logger = Logger.getLogger(DoipClientImpl.class);

    @Override
    public void hello(String id, DoipMessageCallback cb) {
        DoipMessage msg =
                new DoipMessageFactory.DoipMessageBuilder()
                        .createRequest(id, BasicOperations.Hello.getName())
                        .create();
        sendMessage(msg, cb);
    }

    @Override
    public void listOperations(String id, DoipMessageCallback cb) {
        DoipMessage msg =
                new DoipMessageFactory.DoipMessageBuilder()
                        .createRequest(id,BasicOperations.ListOps.getName())
                        .create();
        sendMessage(msg, cb);
    }

    @Override
    public void retrieve(String id, String element, boolean includeElementData, DoipMessageCallback cb) {
        DoipMessage msg =
                new DoipMessageFactory.DoipMessageBuilder()
                        .createRequest(id,BasicOperations.Retrieve.getName())
                        .create();
        if(element != null) msg.header.parameters.addAttribute("element", element);
        if(includeElementData) msg.header.parameters.addAttribute("includeElementData","true");
        sendMessage(msg, cb);
    }

    @Override
    public void create(String targetDOIPServiceID, DigitalObject digitalObject, DoipMessageCallback cb) {
        DoipMessage msg =
                new DoipMessageFactory.DoipMessageBuilder()
                        .createRequest(targetDOIPServiceID,BasicOperations.Create.getName())
                        .setBody(digitalObject)
                        .create();
        sendMessage(msg, cb);
    }

    @Override
    public void update(DigitalObject digitalObject, DoipMessageCallback cb) {
        DoipMessage msg =
                new DoipMessageFactory.DoipMessageBuilder()
                        .createRequest(digitalObject.id,BasicOperations.Update.getName())
                        .setBody(digitalObject)
                        .create();
        sendMessage(msg, cb);
    }

    @Override
    public void delete(String id, DoipMessageCallback cb) {
        DoipMessage msg =
                new DoipMessageFactory.DoipMessageBuilder()
                        .createRequest(id,BasicOperations.Delete.getName())
                        .create();
        sendMessage(msg, cb);
    }

    @Override
    public void search(String id, SearchParameter sp, DoipMessageCallback cb) {
        DoipMessage msg =
                new DoipMessageFactory.DoipMessageBuilder()
                        .createRequest(id,BasicOperations.Search.getName())
                        .addAttributes("query",sp.query)
                        .addAttributes("pageNum",sp.pageNum)
                        .addAttributes("pageSize",sp.pageSize)
                        .addAttributes("type",sp.type)
                        .addAttributes("sortFields",sp.sortFieldsSer)
                        .create();
        sendMessage(msg, cb);
    }

    @Override
    public void sendRawMessage(DoipMessage msg, DoipMessageCallback cb) {
        sendMessage(msg, cb);
    }

    @Override
    public void close(){
        doipChannel.close();
        doipChannel = null;
    };

    @Override
    public void connect(String url){
        try {
            doipChannel = DoipClientChannelGenerator.createDoipClientChannel(url);
            if(doipChannel == null) return;
            doipChannel.connect(url);
            serverURL = url;
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void reconnect() throws DoipConnectException {
        if(serverURL == null) throw (new DoipConnectException("target URL not set, use .connect(url) first"));
        if(doipChannel == null) doipChannel = DoipClientChannelGenerator.createDoipClientChannel(serverURL);
        if(doipChannel == null) return;
        try {
            doipChannel.connect(serverURL);
        }catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getRepoUrl() {
        return serverURL;
    }

    @Override
    public String getRecipientID() {
        return recipientID;
    }

    @Override
    public void setRecipientID(String id) {
        recipientID = id;
    }

    @Override
    public boolean isConnected(){
        return doipChannel != null && doipChannel.isConnected();
    }

    public void sendMessage(DoipMessage msg, DoipMessageCallback cb){
        if(doipChannel == null || !doipChannel.isConnected()){
            logger.warn("channel not connect yet!");
            DoipMessage resp = DoipMessageFactory.createConnectFailedResponse(msg.requestID);
            cb.onResult(resp);
            return;
        }
        msg.setRecipientID(recipientID);
        doipChannel.sendMessage(msg,cb);
    };
}
